import { Message } from 'element-ui'
import store from '@/store'
import tools from './tools'
import { sendSock } from '@/utils/socketSend'

// ice-server config
const iceServerConfig = {
  username: 'hefu01',
  credential: 'hefu123',
  iceServers: ['stun:220.196.49.99:3478', 'turn:220.196.49.99:3478']
}

// 检测是否可用媒体
const hasUserMedia = () => {
  return (
    navigator.getUserMedia ||
    navigator.webkitGetUserMedia ||
    navigator.mozGetUserMedia ||
    navigator.mediaDevices
  )
}

// 获取可用媒体输入和输出设备信息列表
const getDevice = (type) => {
  if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {
    return []
  }

  navigator.mediaDevices.enumerateDevices().then(devices => {
    const typeList = devices.filter(item => item.kind === type)
    typeList.forEach(item => {

    })
    store.commit('conferenceRoom/set_deviceInputList', {
      type,
      list: typeList
    })
  }).catch(err => {
    console.log(err)
  })
}

// 获取本地流当前输入设备ID
const getDevicesId = () => {
  const videoDeviceId = getLocalStream().getVideoTracks()[0].getSettings().deviceId
  const audioDeviceId = getLocalStream().getAudioTracks()[0].getSettings().deviceId
  store.commit('conferenceRoom/set_deviceId', { type: 'audio', id: audioDeviceId })
  store.commit('conferenceRoom/set_deviceId', { type: 'video', id: videoDeviceId })
}

// 启用摄像头麦克风
const openMedia = ({ audioInputId }) => {
  return new Promise((resolve, reject) => {
    if (hasUserMedia()) {
      if (!navigator.mediaDevices) {
        navigator.mediaDevices = {}
      }

      if (!navigator.mediaDevices.getUserMedia) {
        navigator.mediaDevices.getUserMedia = (constrains) => {
          const getUserMeidia =
            navigator.webkitGetUserMedia || navigator.mozGetUserMedia
          if (!getUserMeidia) {
            return Message({
              type: 'error',
              message: '您的浏览器不支持开启摄像头，请更换浏览器！'
            })
          }
          return new Promise((resolve, reject) => {
            getUserMeidia.call(navigator, constrains, resolve, reject)
          })
        }
      }
      const constraints = {
        audio: {
          // 回声消除
          echoCancellation: true,
          // 降噪
          noiseSuppression: true
        },
        video: {
          frameRate: {
            min: 15,
            max: 30
          }
        }
      }
      if (audioInputId) {
        constraints.audio.deviceId = audioInputId
      }

      navigator.mediaDevices
        .getUserMedia(constraints)
        .then((stream) => {
          if (!getLocalStream() || !getLocalStream().active) {
            store.commit('conferenceRoom/add_selfStream', stream)
          }
          resolve(stream)
        })
        .catch((err) => {
          resolve(new MediaStream())
          reject(err)
        })
    }
  })
}

// 获取自己的媒体流
const getLocalStream = () => {
  let stream
  store.state.conferenceRoom.cf_members.forEach(item => {
    if (tools.isSelf(item.id)) {
      stream = item.stream
    }
  })
  return stream
}

// 切换自己的麦克风
const changeAudio = (audioInputId) => {
  openMedia({ audioInputId }).then(stream => {
    const audioTracks = stream.getAudioTracks()
    const cfMembers = store.state.conferenceRoom.cf_members
    cfMembers.forEach(item => {
      if (item.peer) {
        const senders = item.peer.getSenders()
        senders.forEach(it => {
          if (it.track.kind === 'audio') {
            // 替换媒体轨道
            it.replaceTrack(audioTracks.filter(item => item.enabled)[0])
          }
        })
      }
    })
    // 移除本地流原先的audioTrack
    if (getLocalStream().getAudioTracks().filter(item => item.readyState === 'ended')) {
      muteMicPhone()
      getLocalStream().removeTrack(getLocalStream().getAudioTracks().filter(item => item.readyState === 'live')[0])
    }
    // 将新的audioTrack塞入本地流
    getLocalStream().addTrack(audioTracks.filter(item => item.enabled)[0])
    // 切换了设备
    store.commit('conferenceRoom/set_ifChangeInput', true)
  })
}

// 静音麦克风
const muteMicPhone = (stream) => {
  let audioTracks
  if (stream) {
    audioTracks = stream.getAudioTracks()
  } else {
    audioTracks = getLocalStream().getAudioTracks()
  }
  audioTracks.forEach(item => {
    if (item.enabled) {
      item.enabled = false
    }
  })
}

// 取消静音麦克风
const cancelMuteMicPhone = () => {
  const audioTracks = getLocalStream().getAudioTracks()
  audioTracks.forEach(item => {
    if (!item.enabled) {
      item.enabled = true
    }
  })
}

// 获取视频中音量输出大小
const getVolume = stream => {
  return new Promise((resolve, reject) => {
    const context = new AudioContext()
    const timer = setInterval(() => {
      if (stream.getAudioTracks().length) {
        const mediaStreamSource = context.createMediaStreamSource(stream)
        const scriptProcessor = context.createScriptProcessor(4096, 1, 1)
        mediaStreamSource.connect(scriptProcessor)
        scriptProcessor.connect(context.destination)
        resolve(scriptProcessor)
        clearInterval(timer)
      }
    }, 100)
  })
}

// 关闭摄像头
const closeCamera = () => {
  const videoTracks = getLocalStream().getVideoTracks()
  videoTracks.forEach(item => {
    if (item.enabled) {
      item.stop()
    }
  })
}

// 打开摄像头
const openCamera = () => {
  openMedia({}).then(stream => {
    const videoTracks = stream.getVideoTracks()
    const cfMembers = store.state.conferenceRoom.cf_members
    cfMembers.forEach(item => {
      if (item.peer) {
        const senders = item.peer.getSenders()
        senders.forEach(it => {
          if (it.track.kind === 'video') {
            // 替换媒体轨道
            it.replaceTrack(videoTracks.filter(item => item.enabled)[0])
          }
        })
      }
    })
    // 移除本地流原先的videoTrack
    if (getLocalStream().getVideoTracks().filter(item => item.readyState === 'ended')) {
      getLocalStream().removeTrack(getLocalStream().getVideoTracks().filter(item => item.readyState === 'ended')[0])
    }
    // 将新的videoTrack塞入本地流
    getLocalStream().addTrack(videoTracks.filter(item => item.enabled)[0])
  })
}

// 建立peerConnection
const getPeerConnection = (userID) => {
  return new Promise((resolve, reject) => {
    const iceServer = {
      iceServers: [
        {
          url: iceServerConfig.iceServers[0]
        },
        {
          url: iceServerConfig.iceServers[1],
          username: iceServerConfig.username,
          credential: iceServerConfig.credential
        }
      ]
    }
    // 兼容浏览器写法
    const PeerConnection = (window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection)

    // 建立连接
    const peer = new PeerConnection(iceServer)

    // 接收候选人状态变化
    peer.oniceconnectionstatechange = (e) => {
      // 反向连接
      if (e.currentTarget.iceConnectionState === 'disconnected') {
        store.commit('conferenceRoom/close_peer', userID)
        store.commit('conferenceRoom/reset_mediaStream', userID)
        getPeerConnection(userID).then(peer => {
          addTracks(peer, getLocalStream())
          if (store.state.conferenceRoom.cf_type === 'videoCall') {
            // 视频通话重连
            sendSock({
              type: '2.1.11',
              body: {
                msg_type: 4,
                msg_id_length: store.state.conferenceRoom.cf_id.length,
                msg_id: store.state.conferenceRoom.cf_id
              }
            })
          } else {
            // 会议室重连
            sendSock({
              type: '4.2.3',
              body: {
                msg_type: 4,
                cf_id: store.state.conferenceRoom.cf_id,
                id: userID
              }
            })
          }
        })
      }
    }

    // 接收媒体流
    peer.ontrack = (e) => {
      store.commit('conferenceRoom/add_track', {
        id: userID,
        track: e.track
      })
    }

    // 发送ICE候选到其他客户端
    peer.onicecandidate = (e) => {
      if (e.candidate && e.candidate.candidate) {
        // 判断当前是视频通话还是视频会议
        if (store.state.conferenceRoom.cf_type === 'videoCall') {
          sendSock({
            type: '2.1.11',
            body: {
              msg_type: 3,
              msg_id_length: store.state.conferenceRoom.cf_id.length,
              msg_id: store.state.conferenceRoom.cf_id,
              candidate_type: e.candidate.sdpMLineIndex === 0 ? 1 : 2,
              candidate_content: e.candidate.candidate
            }
          })
        } else {
          sendSock({
            type: '4.2.3',
            body: {
              msg_type: 3,
              cf_id: store.state.conferenceRoom.cf_id,
              id: userID,
              candidate_type: e.candidate.sdpMLineIndex === 0 ? 1 : 2,
              candidate_content: e.candidate.candidate
            }
          })
        }
      }
    }

    // 向会议成员列表中的当前成员添加peer
    store.commit('conferenceRoom/add_peer', { id: userID, peer })

    resolve(peer)
  })
}

// 添加媒体流到当前peer
const addTracks = (peer, stream) => {
  const audioTracks = stream.getAudioTracks()
  const videoTracks = stream.getVideoTracks()

  if (audioTracks.some(item => item.enabled)) {
    peer.addTrack(audioTracks.filter(item => item.enabled)[0])
  }
  if (videoTracks.some(item => item.enabled)) {
    peer.addTrack(videoTracks.filter(item => item.enabled)[0])
  }
}

// 发送offer，发送本地session描述
const createOffer = (peer, cfID, id) => {
  peer.createOffer().then(desc => {
    peer.setLocalDescription(desc, () => {
      // 判断当前是视频通话还是视频会议
      if (store.state.conferenceRoom.cf_type === 'videoCall') {
        sendSock({
          type: '2.1.11',
          body: {
            msg_type: 1,
            msg_id_length: cfID.length,
            msg_id: cfID,
            spe_msg: peer.localDescription.sdp
          }
        })
      } else {
        sendSock({
          type: '4.2.3',
          body: {
            msg_type: 1,
            cf_id: cfID,
            id,
            msg: peer.localDescription.sdp
          }
        })
      }
    })
  })
}

// 设置远程对象的sdp，生成本地session描述并回复answer
const createAnswer = (peer, sdp, cfID, id) => {
  peer.setRemoteDescription({
    type: 'offer',
    sdp
  }, () => {
    peer.createAnswer().then(desc => {
      peer.setLocalDescription(desc, () => {
        // 判断当前是视频通话还是视频会议

        if (store.state.conferenceRoom.cf_type === 'videoCall') {
          sendSock({
            type: '2.1.11',
            body: {
              msg_type: 2,
              msg_id_length: cfID.length,
              msg_id: cfID,
              spe_msg: peer.localDescription.sdp
            }
          })
        } else {
          sendSock({
            type: '4.2.3',
            body: {
              msg_type: 2,
              cf_id: cfID,
              id,
              msg: peer.localDescription.sdp
            }
          })
        }
      })
    })
  }, err => {
    console.log(err)
  })
}

// 仅设置远程对象的sdp-接收到answer时
const createRemoteSDP = (peer, sdp) => {
  peer.setRemoteDescription({
    type: 'answer',
    sdp
  })
}

// 等待远程sdp的队列
let timer
// // 设置添加候选人
const addIceCandidate = (peer, sdpMidStr, sdpMlineIndexNum, candidate) => {
  if (peer && peer.currentRemoteDescription) {
    if (timer) {
      clearInterval(timer)
    }
    peer.addIceCandidate({
      sdpMid: sdpMidStr,
      sdpMLineIndex: sdpMlineIndexNum,
      candidate
    })
  } else {
    timer = setTimeout(() => {
      addIceCandidate(peer, sdpMidStr, sdpMlineIndexNum, candidate)
    }, 100)
  }
}

export default {
  getDevice,
  getDevicesId,
  openMedia,
  getLocalStream,
  changeAudio,
  muteMicPhone,
  cancelMuteMicPhone,
  getVolume,
  closeCamera,
  openCamera,
  getPeerConnection,
  addTracks,
  createOffer,
  createAnswer,
  createRemoteSDP,
  addIceCandidate
}
